package cn.harry.wx.service.impl;

import cn.harry.common.utils.SecurityUtils;
import cn.harry.common.utils.SysUserUtils;
import cn.harry.sys.entity.SysUser;
import cn.harry.wx.dao.WxAccountDao;
import cn.harry.wx.entity.WxAccount;
import cn.harry.wx.service.WxAccountService;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 公众号账号
 *
 * @author honghh
 * Date 2021-04-08 16:19:27
 * Copyright (C) www.tech-harry.cn
 */
@Slf4j
@Service("wxAccountService")
public class WxAccountServiceImpl extends ServiceImpl<WxAccountDao, WxAccount> implements WxAccountService {

    @Autowired
    WxMpService wxMpService;

    @Override
    public IPage<WxAccount> getPage(WxAccount wxAccount, Integer pageSize, Integer pageNum) {
        LambdaQueryWrapper<WxAccount> wrapper = new LambdaQueryWrapper<>(wxAccount);

        SysUser user = SysUserUtils.getSysUser();
        if (!SecurityUtils.isAdmin(user.getId())) {
            wrapper.eq(WxAccount::getUserId, user.getId());
        }
        if (StrUtil.isNotEmpty(wxAccount.getBeginTime())) {
            wrapper.gt(WxAccount::getCreateTime, wxAccount.getBeginTime());
        }
        if (StrUtil.isNotEmpty(wxAccount.getEndTime())) {
            wrapper.lt(WxAccount::getCreateTime, wxAccount.getEndTime());
        }
        return page(new Page<>(pageNum, pageSize), wrapper);
    }


    @Override
    public WxAccount selectById(Long id) {
        return this.baseMapper.selectById(id);
    }

    @Override
    public int create(WxAccount wxAccount) {
        SysUser user = SysUserUtils.getSysUser();
        wxAccount.setUserId(user.getId());

        log.info("新增公众号配置");
        this.addAccountToRuntime(wxAccount);
        return this.baseMapper.insert(wxAccount);
    }


    @Override
    public int update(Long id, WxAccount wxAccount) {
        wxAccount.setId(id);
        log.info("更新公众号配置");
        wxMpService.removeConfigStorage(wxAccount.getAppid());
        this.addAccountToRuntime(wxAccount);
        return this.baseMapper.updateById(wxAccount);
    }


    @Override
    public int deleteByIds(Long[] ids) {
        return this.baseMapper.deleteBatchIds(Arrays.asList(ids));
    }

    @Override
    public List<WxAccount> getListByUserId(Long userId) {
        if (!SecurityUtils.isAdmin(userId)) {
            return list(new LambdaQueryWrapper<WxAccount>().eq(WxAccount::getUserId, userId));
        } else {
            return list();
        }
    }

    @Override
    public WxAccount selectByAppId(String appid) {
        return getOne(new LambdaQueryWrapper<WxAccount>().eq(WxAccount::getAppid, appid));
    }

    @PostConstruct
    public void loadWxMpConfigStorages() {
        log.info("加载公众号配置...");
        List<WxAccount> accountList = this.list();
        if (accountList == null || accountList.isEmpty()) {
            log.info("未读取到公众号配置，请在管理后台添加");
            return;
        }
        log.info("加载到{}条公众号配置", accountList.size());
        accountList.forEach(this::addAccountToRuntime);
        log.info("公众号配置加载完成");
    }

    /**
     * 添加账号到当前程序，如首次添加需初始化configStorageMap
     *
     * @param entity
     */
    private synchronized void addAccountToRuntime(WxAccount entity) {
        String appid = entity.getAppid();
        WxMpDefaultConfigImpl config = entity.toWxMpConfigStorage();
        try {
            wxMpService.addConfigStorage(appid, config);
        } catch (NullPointerException e) {
            log.info("需初始化configStorageMap...");
            Map<String, WxMpConfigStorage> configStorages = new HashMap<>(4);
            configStorages.put(appid, config);
            wxMpService.setMultiConfigStorages(configStorages, appid);
        }
    }
}